package cn.yotta.user.core.server.iface.login.impl;

import cn.yotta.common.utils.param.AssertUtil;
import cn.yotta.user.api.params.login.BaseLoginRequest;
import cn.yotta.user.core.server.dto.user.UserDto;
import cn.yotta.user.core.server.exception.user.UserNotFindException;
import cn.yotta.user.core.server.exception.user.UserStateException;
import cn.yotta.user.core.server.iface.login.LoginProvider;
import cn.yotta.user.web.autoconfiguration.exception.UserLoginException;
import lombok.extern.slf4j.Slf4j;

import static cn.yotta.user.api.error.UserCommonErrorCode.*;

/**
 * @author wyaoyao
 * @date 2022/11/9 8:45
 */
@Slf4j
public abstract class AbstractLoginProvider<T extends BaseLoginRequest> implements LoginProvider<T> {


    @Override
    public UserDto auth(T loginRequest) {
        // 获取用户唯一标识
        final String principal = this.getPrincipal(loginRequest);
        preLoadUser(loginRequest);
        final UserDto user = this.loadUser(principal);
        afterLoadUser(user,loginRequest);
        AssertUtil.nonNull(user, USER_NOT_EXISTS.getCode());
        additionalAuthenticationChecks(user, loginRequest);
        checkUserStatus(user);
        return user;
    }

    /**
     * 加载用户后回调，默认空实现，可有子类扩展实现
     */
    protected void afterLoadUser(UserDto user, T loginRequest) {
    }

    /**
     * 校验用户状态
     */
    protected void checkUserStatus(UserDto user) throws UserLoginException {
        if (!user.getEnabled()) {
            throw new UserStateException(USER_IS_DISABLED.getCode());
        }
        if (user.getLocked()) {
            throw new UserStateException(USER_IS_LOCKED.getCode());
        }
    }

    /**
     * 加载用户前回调，默认空实现，可有子类扩展实现
     */
    protected void preLoadUser(T request) throws UserLoginException {

    }

    /**
     * 根据用户唯一凭证加载用户
     */
    protected abstract UserDto loadUser(String principal) throws UserNotFindException;

    /**
     * 其他用户校验：子类实现，比如密码登录，可以在此处实现密码是否匹配的校验
     */
    protected abstract void additionalAuthenticationChecks(UserDto user,
                                                           T baseLoginRequest);
}
